package com.atguigu.common.utils;

import com.atguigu.common.exception.SelfBusException;
import com.atguigu.common.result.ResultCodeEnum;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import java.util.Date;

@Component
public class JwtUtil {

    // 设置token过期时间
    private static long tokenExpiration = 60 * 60 * 1000L;
    // 设置token加密密钥
    /**
     * 这个字符串不能随意更改，因为它直接影响到生成的密钥值。
     * 如果更改了这个字符串，之前生成的 JWT 令牌将无法被正确验证，导致认证失败。
     * 因此，除非有特殊需求（如密钥轮换），否则不建议随意更改。
     */
    private static SecretKey tokenSignKey = Keys.hmacShaKeyFor("M0PKKI6pYGVWWfDZw90a0lTpGYX1d4AQ".getBytes());

    /**
     * 生成 JWT 令牌。
     *
     * @param userId 用户 ID
     * @param username 用户名
     * @return 生成的 JWT 令牌字符串
     */
    public static String createToken(Long userId, String username) {
        return Jwts.builder()
                // 设置 JWT 头信息
                .setSubject("USER_INFO")
                // 设置过期时间
                .setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))
                // 添加用户 ID 自定义声明
                .claim("userId", userId)
                // 添加用户名自定义声明
                .claim("username", username)
                // 设置签名和密钥
                .signWith(tokenSignKey)
                // 使用 GZIP 压缩
                .compressWith(CompressionCodecs.GZIP)
                // 生成并返回 JWT 令牌字符串
                .compact();
    }


    /**
     * 解析 JWT 令牌并返回其中的 Claims 信息。
     *
     * @param token 需要解析的 JWT 令牌字符串
     * @return 解析后的 Claims 信息
     * @throws SelfBusException 如果令牌过期或无效，抛出自定义异常
     */
    public static Claims parseToken(String token) {
        try {
            // 使用 Jwts 解析生成器
            Jws<Claims> claimsJws = Jwts.parserBuilder()
                    // 设置用于签名验证的密钥
                    .setSigningKey(tokenSignKey)
                    // 构建解析器
                    .build()
                    // 解析 JWT 令牌
                    .parseClaimsJws(token);
            // 返回解析后的 Claims 信息
            return claimsJws.getBody();

        } catch (ExpiredJwtException e) {
            // 如果令牌过期，抛出自定义异常
            throw new SelfBusException(ResultCodeEnum.TOKEN_EXPIRED);
        } catch (JwtException e) {
            // 如果令牌无效，抛出自定义异常
            throw new SelfBusException(ResultCodeEnum.TOKEN_INVALID);
        }
    }

}